package qiongqi

import (
	"cdam/enum"
	"cdam/models"
	"cdam/util"
	"fmt"
	"math/rand"
	"strconv"
	"time"
)

// 定义流程运行的接口； 目前只提供两个方法
type ModelEnginee interface {

	// 解析流程并保存到数据库中
	DeployProcess(parameter ParseResult) (int64,error)

}

// 链接接口与实现
var _ ModelEnginee = new(QiongqiProcessModel)

type ProcessNode struct {
	NodeID                        string            // 节点ID
	NodeName                      string            // 节点名称
	NodeType                      enum.NodeType     // 节点类型
	Routers                       []*RouterResult   // 节点路由
	Properties                    []*PropertyResult // 节点属性
	CandidateUsersExpressions     []string          // 候选人表达式
	AssignExpressions             []string          // 分发人表达式
	CandidateRolesExpressions     []string          // 候选角色表达式
	CandidateGroupsExpressions    []string          // 候选组表达式
	FormResult                    *NodeFormResult   // 节点表单
	CandidatePositionsExpressions []string          // 候选人职位
	Cronexpresion                 string            // cron表达式
	ID                            int64             // 数据库中的主键ID
}

// 定义实现
type QiongqiProcessModel struct {
	Result       ParseResult
	Tenant       int64
	Name         string
	XmlData      string
	Nodes        []*NodeResult
	ProcessNodes []*ProcessNode
	ProcessId    int64

	_EventProcessCode   		string
	_EventNodeCode      		string
	_EventNodeName      		string
	_EventNodeId        		int64
	_EventNodeParameter 		string
	_EventTriggerExpression		string
}

// 部署流程
func (q QiongqiProcessModel) DeployProcess(parameter ParseResult) (int64,error) {
	q.Nodes = parameter.Nodes
	err := q.CreateProcess(parameter)
	if err == nil {
		if err = q.CreateNodes(); err == nil {
			// 创建候选人
			err = q.CreateCandidate()
			if err != nil {
				return 0,err
			}
			// 创建表单
			err = q.CreateForm()
			if err != nil {
				return 0,err
			}

			err = q.CreateRoutes()
			if err != nil {
				return 0,err
			}
			if err = q.CreateMessage(parameter); err != nil {
				return 0, err
			}else{
				return q.ProcessId,nil
			}
		} else{
			return 0,err
		}
	}else{
		return 0,err
	}
}

var model = new (QiongqiProcessModel)

type NewProcessModeParameter struct {
	Result  *ParseResult
	Tenant  int64
	Name    string
	XmlData string
}

func NewQiongqiProcessModel(param NewProcessModeParameter) ModelEnginee {
	if model == nil {
		model = new(QiongqiProcessModel)
	}
	model.Tenant = param.Tenant
	model.XmlData = param.XmlData
	model.Name = param.Name
	model.Result = *param.Result
	model.Nodes = param.Result.Nodes
	return model
}

// 创建流程信息
func (q *QiongqiProcessModel) CreateProcess(param ParseResult) error {
	var process = new(models.FlowProcess)
	process.Id = rand.NewSource(time.Now().UnixNano()).Int63()
	process.Code = param.FlowId         //["FlowId"].(string)
	process.Status = param.FlowStatus   //["FlowStatus"].(int)
	process.Version = param.FlowVersion // ["FlowVersion"].(int64)
	process.Createdate = time.Now()
	process.Tenant = q.Tenant
	process.Name = q.Name
	process.Xmldata = q.XmlData
	condition := map[string]string{}
	condition["code"] = process.Code
	// 设置版本
	if lst, err := models.GetProcessByCondition(condition); err == nil {
		// 设置版本
		if len(lst) > 0 {
			process.Version = lst[0].Version+1
		}else{
			process.Version = 1
		}
		// 修改其余版本的流程为 挂起状态
		for _,pro := range lst {
			pro.Status = 0
			_ = models.UpdateTFlowProcessById(&pro)
		}
	}
	_, err := models.AddTFlowProcess(process)
	q.ProcessId = process.Id
	q._EventProcessCode = process.Code
	_, err = models.DeleteEventsByProcessCode(process.Code)
	return err
}

// 创建节点信息
func (q *QiongqiProcessModel) CreateNodes() error {
	processNodes := []*ProcessNode{}
	for _, node :=range q.Nodes {
		nod := new(models.FlowProcessNode)
		nod.Id = rand.New(util.Seed).Int63n(100000000)
		fmt.Println("node id is ", nod.Id)
		nod.Processid = q.ProcessId
		nod.Code = node.NodeID
		nod.Name = node.NodeName
		nod.Cronexpression = node.Cronexpresion
		nod.TypeCode = node.NodeType.String()
		nod.Createdate = time.Now()
		nod.FormId = node.FormResult.ID
		nod.MessageId = node.MessageId
		nod.MessageRef = node.MessageRef

		processNode := new(ProcessNode)
		processNode.ID = int64(nod.Id)
		processNode.NodeType =  node.NodeType
		processNode.NodeName =  node.NodeName
		processNode.FormResult = node.FormResult
		processNode.Routers = node.Routers
		processNode.NodeID = node.NodeID
		processNode.AssignExpressions = node.AssignExpressions
		processNode.CandidateGroupsExpressions = node.CandidateGroupsExpressions
		processNode.CandidatePositionsExpressions = node.CandidatePositionsExpressions
		processNode.CandidateRolesExpressions = node.CandidateRolesExpressions
		processNode.CandidateUsersExpressions = node.CandidateUsersExpressions
		processNode.Cronexpresion = node.Cronexpresion
		processNodes = append(processNodes,processNode)


		q._EventNodeCode = nod.Code
		q._EventNodeName = nod.Name
		q._EventNodeId = nod.Id
		// 如果开始节点为   新增事件到开始节点中
		if nod.TypeCode == enum.TimeEvent.String() {
			q._EventTriggerExpression = nod.Cronexpression
			_ = q.CreateStartProcessForTimeTrigger(enum.EVENTTYPE_STARTTIMEEVENT)
		}
		if nod.TypeCode == enum.MessageEvent.String() {
			q._EventTriggerExpression = nod.MessageRef
			_ = q.CreateStartProcessForTimeTrigger(enum.EVENTTYPE_STARTMESSAGEEVENT)
		}
		if _, err := models.AddFlowProcessNode(nod); err != nil {
			return err
		}
	}
	q.ProcessNodes = processNodes
	return nil
}

// 创建候选人
func (q *QiongqiProcessModel)CreateCandidate() error  {
	for _,node := range q.ProcessNodes{
		for _, candidateUser := range node.CandidateUsersExpressions {
			assign := new(models.FlowProcessNodeassign)
			assign.Id = int(rand.New(util.Seed).Int63n(100000000))
			assign.Processid = q.ProcessId
			assign.Nodeid = node.ID
			assign.UserType = enum.CandidateUser.String()
			assign.Createdate = time.Now()
			assign.Expression = candidateUser
			if _, err := models.AddFlowProcessNodeassign(assign); err != nil {
				return err
			}else{
				continue
			}
		}

		for _, candidateRole := range node.CandidateRolesExpressions {
			assign := new(models.FlowProcessNodeassign)
			assign.Id = int(rand.New(util.Seed).Int63n(100000000))
			assign.Processid = q.ProcessId
			assign.Nodeid = node.ID
			assign.UserType = enum.CandidateRole.String()
			assign.Createdate = time.Now()
			assign.Expression = candidateRole
			// todo
			if _, err := models.AddFlowProcessNodeassign(assign); err != nil {
				return err
			}else{
				continue
			}
		}

		// 候选组
		for _, candidateGroup := range node.CandidateGroupsExpressions {
			assign := new(models.FlowProcessNodeassign)
			assign.Id = int(rand.New(util.Seed).Int63n(100000000))
			assign.Processid = q.ProcessId
			assign.Nodeid = node.ID
			assign.UserType = "candidateGroup"
			assign.Createdate = time.Now()
			assign.Expression = candidateGroup
			// todo
			if _, err := models.AddFlowProcessNodeassign(assign); err != nil {
				return err
			}else{
				continue
			}

		}
		// 创建分配人
		for _, ass := range node.AssignExpressions {
			assign := new(models.FlowProcessNodeassign)
			assign.Id = int(rand.New(util.Seed).Int63n(100000000))
			assign.Processid = q.ProcessId
			assign.Nodeid = node.ID
			assign.UserType = "assignUser"
			assign.Createdate = time.Now()
			assign.Expression = ass
			// todo
			if _, err := models.AddFlowProcessNodeassign(assign); err != nil {
				return err
			}else{
				continue
			}
		}
	}
	return nil
}

// 创建表单信息
func (q *QiongqiProcessModel) CreateForm() error {
	for _,node := range q.ProcessNodes {
		form := new(models.FlowProcessForm)
		form.Id = int(rand.New(util.Seed).Int63n(100000000))
		form.Createdate = time.Now()
		form.Nodeid = node.ID
		form.Processid = q.ProcessId
		form.Code = node.FormResult.ID
		form.TypeCode = "1"
		// todo
		if _, err := models.AddFlowProcessForm(form); err != nil {
			return err
		}else{
			continue
		}
	}
	return nil
}

// 创建路由
func (q *QiongqiProcessModel) CreateRoutes() error {
	for _,node := range q.ProcessNodes {
		for _, qiongqiRoute := range node.Routers {
			route := new(models.FlowProcessRoute)
			route.Id = int(rand.New(util.Seed).Int63n(100000000))
			route.Createdate = time.Now()
			route.ProcessId = q.ProcessId
			route.Code = qiongqiRoute.Code
			route.Targeid = qiongqiRoute.TargetNodeID
			route.Explain = qiongqiRoute.Explain
			route.Expression = qiongqiRoute.Expression
			route.Sourceid = node.NodeID
			// 创建路由
			// todo
			if _, err := models.AddFlowProcessRoute(route); err != nil {
				return err
			}else{
				continue
			}
		}
	}
	return nil
}

func (p *QiongqiProcessModel) CreateStartProcessForTimeTrigger(messagetype enum.EventType) error {
	timeTrigger := models.Event{}
	processSuffix := p._EventProcessCode + "_" + p._EventNodeCode
	fullName := p.Name + "_" + p._EventNodeName
	timeTrigger.Id = rand.New(util.Seed).Int63n(100000000)
	timeTrigger.Code = strconv.FormatInt(p.ProcessId,10) + "_" + processSuffix
	timeTrigger.Name = fullName
	timeTrigger.TriggerExpression = p._EventTriggerExpression
	timeTrigger.Processid.SetValue(p.ProcessId)
	timeTrigger.Nodeid.SetValue(p._EventNodeId)
    timeTrigger.Instancenodeid.Valid = false
    timeTrigger.Instanceid.Valid = false
    timeTrigger.Processcode = p._EventProcessCode
    timeTrigger.Nodecode = p._EventNodeCode
	timeTrigger.Createdate = time.Now()
	timeTrigger.Updatedate = time.Now()
	timeTrigger.Status = enum.EVENTINT.String()
	timeTrigger.Level = enum.EVENTLEVEL_PROCESS.String()
	timeTrigger.Type = messagetype.String()
	timeTrigger.Isdelete = 0
	_,err := models.AddEvent(&timeTrigger)
	return err
}


func (q *QiongqiProcessModel) CreateMessage(parameter ParseResult) error {
	if parameter.Messages != nil {
		for _, message := range parameter.Messages {
			m := models.Message{}
			m.Id = rand.New(util.Seed).Int63n(100000000)
			m.Code = message.Id
			m.Name = message.Name
			_, err := models.AddMessage(&m)
			if err != nil {
				return err
			}else{
				continue
			}
		}
		return nil
	}else{
		return nil
	}
}


